﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using iMon.DisplayApi;

namespace DVBViMon
{
    public partial class ScrollTextTimerVFD : System.Windows.Forms.Timer
    {
        #region enums and fields

        private ScrollStates scrollState = ScrollStates.Init;
        private const int waitTicks = 3;
        private int ScrollRepeatCounter;
        private bool timerLoopActive;

        public enum ScrollStates
        {
            Init,
            WaitAfterInit,
            ScrollLine1,
            WaitLine1Finished,
            ResetLine1,
            WaitResetLine1Finished,
            ScrollLine2,
            WaitLine2Finished,
            ResetLine2,
            WaitResetLine2Finished
        }

        private int scrollPositionLine1;
        private int scrollPositionLine2;

        public string ScrollingTextLine1 { get; private set; }
        public string ScrollingTextLine2 { get; private set; } 
        private int waitTickCounter;
        private bool ContinuousScrolling;

        #endregion

        #region ctor

        /// <summary>
        /// Initializes a new instance of the <see cref="ScrollTextTimerVFD"/> class.
        /// </summary>
        /// <param name="interval">The scroll interval time in ms.</param>
        public ScrollTextTimerVFD(int interval = 500)
        {
            this.Interval = interval;
            InitializeComponent();
        }

        #endregion

        #region overrides

        protected override void OnTick(EventArgs e)
        {
            if (!this.timerLoopActive)
            {
                this.timerLoopActive = true;
                this.DoTheScrolling();
                this.timerLoopActive = false;
            }

            base.OnTick(e);
        }

        #endregion

        #region implementation

        /// <summary>
        /// Sets the VFD text with scrolling.
        /// </summary>
        /// <param name="line1">The line1.</param>
        /// <param name="line2">The line2.</param>
        public void SetVfdText( string line1, string line2)
        {
            this.Stop();
            this.ScrollingTextLine1 = convertDE2EN(line1);
            this.ScrollingTextLine2 = convertDE2EN(line2);
            this.ScrollingTextLine1 = this.CenterString(this.ScrollingTextLine1);
            this.ScrollingTextLine2 = this.CenterString(this.ScrollingTextLine2);
            this.scrollPositionLine1 = 0;
            this.scrollPositionLine2 = 0;
            this.scrollState = ScrollStates.Init;
            this.ScrollRepeatCounter = Properties.Settings.Default.ScrollRepeat;
            this.ContinuousScrolling = Properties.Settings.Default.continuousScrolling;
            this.OutLines(this.ScrollingTextLine1, this.ScrollingTextLine2);

            if (this.ScrollingTextLine1.Length > 16 || this.ScrollingTextLine2.Length > 16)
                this.Start();
        }


        /// <summary>
        /// Does the scrolling.
        /// </summary>
        private void DoTheScrolling()
        {
            if (!this.ContinuousScrolling)
            {
                if (this.ScrollRepeatCounter == 0)
                {
                    this.Stop();
                    return;
                }
            }

            string line1 = this.ScrollingTextLine1;
            string line2 = this.ScrollingTextLine2;
            int maxScrollCountLine1 = this.ScrollingTextLine1.Length - 16 + 8;
            int maxScrollCountLine2 = this.ScrollingTextLine2.Length - 16 + 8;

            switch (this.scrollState)
            {
                case ScrollStates.Init:
                    waitTickCounter = waitTicks;
                    this.scrollPositionLine1 = 0;
                    this.scrollPositionLine2 = 0;
                    this.scrollState = ScrollStates.WaitAfterInit;
                    break;

                case ScrollStates.WaitAfterInit:
                    if (waitTickCounter != 0)
                    {
                        waitTickCounter--;
                    }
                    else
                    {
                        if (this.ScrollingTextLine1.Length > 16)
                            this.scrollState = ScrollStates.ScrollLine1;
                        else
                            this.scrollState = ScrollStates.ScrollLine2;
                    }
                    break;

                case ScrollStates.ScrollLine1:
                    this.scrollPositionLine1++;
                    line1 = ScrollingTextLine1.Substring(scrollPositionLine1);
                    OutLines(line1, line2);
                    if (scrollPositionLine1 == maxScrollCountLine1)
                    {
                        this.waitTickCounter = waitTicks;
                        this.scrollPositionLine1 = 0;
                        this.scrollState = ScrollStates.WaitLine1Finished;
                    }
                    break;

                case ScrollStates.WaitLine1Finished:
                    if (waitTickCounter != 0)
                    {
                        waitTickCounter--;
                    }
                    else
                    {
                        this.scrollState = ScrollStates.ResetLine1;
                    }
                    break;

                case ScrollStates.ResetLine1:
                    OutLines(line1, line2);
                    this.waitTickCounter = waitTicks;
                    this.scrollState = ScrollStates.WaitResetLine1Finished;
                    break;

                case ScrollStates.WaitResetLine1Finished:
                    if (waitTickCounter != 0)
                    {
                        waitTickCounter--;
                    }
                    else
                    {
                        if (this.ScrollingTextLine2.Length > 16)
                            this.scrollState = ScrollStates.ScrollLine2;
                        else
                        {
                            this.scrollState = ScrollStates.ScrollLine1;
                            if (!this.ContinuousScrolling)
                                this.ScrollRepeatCounter--;
                        }
                    }
                    break;

                case ScrollStates.ScrollLine2:
                    this.scrollPositionLine2++;
                    line2 = ScrollingTextLine2.Substring(scrollPositionLine2);
                    OutLines(line1, line2);
                    if (scrollPositionLine2 == maxScrollCountLine2)
                    {
                        this.waitTickCounter = waitTicks;
                        this.scrollPositionLine2 = 0;
                        this.scrollState = ScrollStates.WaitLine2Finished;
                    }
                    break;

                case ScrollStates.WaitLine2Finished:
                    if (waitTickCounter != 0)
                    {
                        waitTickCounter--;
                    }
                    else
                    {
                        this.scrollState = ScrollStates.ResetLine2;
                    }
                    break;

                case ScrollStates.ResetLine2:
                    OutLines(line1, line2);
                    this.waitTickCounter = waitTicks;
                    this.scrollState = ScrollStates.WaitResetLine2Finished;
                    break;

                case ScrollStates.WaitResetLine2Finished:
                    if (waitTickCounter != 0)
                    {
                        waitTickCounter--;
                    }
                    else
                    {
                        if (this.ScrollingTextLine1.Length > 16)
                            this.scrollState = ScrollStates.ScrollLine1;
                        else
                            this.scrollState = ScrollStates.ScrollLine2;
                        if (!this.ContinuousScrolling)
                            this.ScrollRepeatCounter--;
                    }
                    break;

            }
        }

        /// <summary>
        /// Outputs the lines to the VFD display.
        /// </summary>
        /// <param name="line1">The line1.</param>
        /// <param name="line2">The line2.</param>
        private void OutLines(string line1, string line2)
        {
            try
            {
                iMonNativeApi.IMON_Display_SetVfdText(line1, line2);
            }
            catch (Exception)
            {
            }
        }


        /// <summary>
        /// Converts the DE e2 EN.
        /// </summary>
        /// <param name="inString">The in string.</param>
        /// <returns></returns>
        private string convertDE2EN(string inString)
        {
            string temp = inString.Replace("ä", "ae");
            temp = temp.Replace("Ä", "Ae");
            temp = temp.Replace("ö", "oe");
            temp = temp.Replace("Ö", "Oe");
            temp = temp.Replace("ü", "ue");
            temp = temp.Replace("Ü", "Ue");
            temp = temp.Replace("ß", "ss");

            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < temp.Count(); ++i)
            {
                if (Convert.ToInt16(temp[i]) > 0x007f)
                    sb.Append('_');
                else
                {
                    sb.Append(temp[i]);
                }
            }
            return (sb.ToString());
        }

        /// <summary>
        /// Centers the string.
        /// </summary>
        /// <param name="inString">The in string.</param>
        /// <returns></returns>
        private string CenterString(string inString)
        {
            if (inString.Length < 15)
            {
                int insertedBlanks = (16 - inString.Length) / 2;
                string centered = new string(' ', insertedBlanks);
                return (centered + inString);
            }
            else
            {
                return (inString);
            }
        }
        #endregion
    }
}
